package com.pzl.router;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import dalvik.system.BaseDexClassLoader;
import dalvik.system.DexFile;

public class JumpUtil {

    private static JumpUtil instance = new JumpUtil();

    /**
     * 缓存各组件模块所有的activity class,在application初始化缓存所有
     */
    private Map<String, Class<? extends Activity>> classes;

    private Context context;

    private JumpUtil() {
        classes = new HashMap<>();
    }

    public void init(Context context) {
        instance.context = context;

        /**
         * 找到同一包名下所有的工具实现类，通过回调接口，把所有模块里面的activity class 缓存到容器
         */
        List<String> classPath = getClassName("com.pzl.path.util");
        for (String className : classPath) {
            try {
                Class<?> utilClass = Class.forName(className);
                if (IJump.class.isAssignableFrom(utilClass)) {
                    Log.i("jinx","init 查找的包名下所有的工具类："+className);
                    IJump iJump = (IJump) utilClass.newInstance();
                    iJump.saveActivityClass();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static JumpUtil getInstance() {
        return instance;
    }

    /**
     * 缓存activity class 类对象
     *
     * @param key 一般申明为唯一的路径   if(!rootProject.ext.android.is_application){
     *         implementation project(path: ':cart')
     *         implementation project(path: ':member')
     *     }
     * @param cls
     */
    public void saveActivityClass(String key, Class cls) {
        if (classes.containsKey(key)) return;
        classes.put(key, cls);
    }

    public Class<? extends Activity> getActivityClass(String key) {
        return classes.get(key);
    }

    /**
     * activity 跳转
     *
     * @param path
     */
    public void jump(String path) {
        Class activityClass = getActivityClass(path);
        if (activityClass == null) {
            Toast.makeText(context, path + " 不存在", Toast.LENGTH_SHORT).show();
            return;
        }
        Log.i("jinx", activityClass.getName());
        Intent intent = new Intent(context, activityClass);
        context.startActivity(intent);
    }


    /**
     * 通过包名获取这个包下面的所有的类名
     *
     * @param packageName
     * @return
     */
    private List<String> getClassName(String packageName) {
        List<String> classList = new ArrayList<>();
        try {
            //把当前应有的apk存储路径给dexFile
            ArrayList<DexFile> multiDex = getMultiDex();
            Log.i("jinx","dexFile size = "+multiDex.size());
            for (DexFile dex : multiDex) {
                Enumeration<String> entries = dex.entries();
                while (entries.hasMoreElements()) {
                    String className = (String) entries.nextElement();
                    if (className.contains(packageName)) {
                        classList.add(className);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        Log.i("jinx","查找包名下 所有类："+ Arrays.toString(classList.toArray()));
        return classList;
    }

    /**
     * 通过包名获取这个包下面的所有的类名
     * @param packageName
     * @return
     */
    private List<String> getClassName2(String packageName) {
        //创建一个class对象的集合
        List<String> classList = new ArrayList<>();
        try {
            //把当前应有的apk存储路径给dexFile
            DexFile df = new DexFile(context.getPackageCodePath());
            Enumeration<String> entries = df.entries();
            while (entries.hasMoreElements()) {
                String className = (String) entries.nextElement();
                Log.i("jinx","className = "+className);
                if (className.contains(packageName)) {
                    classList.add(className);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return classList;
    }


    //dex分包的话 须这么干
    public ArrayList<DexFile> getMultiDex()
    {
        BaseDexClassLoader dexLoader = (BaseDexClassLoader) getClassLoader();
        Field f = getField("pathList", getClassByAddressName("dalvik.system.BaseDexClassLoader"));
        Object pathList = getObjectFromField(f, dexLoader);
        Field f2 = getField("dexElements", getClassByAddressName("dalvik.system.DexPathList"));
        Object[] list = getObjectFromField(f2, pathList);
        Field f3 = getField("dexFile", getClassByAddressName("dalvik.system.DexPathList$Element"));

        ArrayList<DexFile> res = new ArrayList<>();
        for(int i = 0; i < list.length; i++)
        {
            DexFile d = getObjectFromField(f3, list[i]);
            res.add(d);
        }

        return res;
    }

    private Field getField(String className, Class<?> clazz) {
        Field field = null;
        try {
            field = clazz.getDeclaredField(className);
            field.setAccessible(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return field;
    }

    public ClassLoader getClassLoader()
    {
        return Thread.currentThread().getContextClassLoader();
    }


    public Class<?> getClassByAddressName(String classAddressName)
    {
        Class mClass = null;
        try
        {
            mClass = Class.forName(classAddressName);
        } catch(Exception e)
        {
        }
        return mClass;
    }


    public <T extends Object> T getObjectFromField(Field field, Object arg)
    {
        try
        {
            field.setAccessible(true);
            return (T) field.get(arg);
        } catch(Exception e)
        {
            e.printStackTrace();
            return null;
        }
    }

}
